package net.wicp.tams.common.metrics.core;

import com.codahale.metrics.*;

import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import net.wicp.tams.common.metrics.utility.Utils;
import net.wicp.tams.common.metrics.utility.TsLogger;


public class TsMetricFacotory {

    private final static MetricRegistry metrics = new MetricRegistry();
    private final static JsonReporter reporter;

    private final String factoryId;
    private final String IpAddress;
    private final String serviceName;

    static {
        TsLogger.getTamsLogger();
        reporter = JsonReporter.forRegistry(metrics)
                .outputTo(TsLogger.getTamsLogger())
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(60, TimeUnit.SECONDS);
    }

    public TsMetricFacotory(String serviceName) {
        this.serviceName = serviceName;
        factoryId = String.format("%d_%d", Utils.getPid(), System.currentTimeMillis());
        IpAddress = Utils.getLocalAddress();
    }

    protected String getIpAddress() {
        return IpAddress;
    }

    protected String getFactoryId() {
        return factoryId;
    }

    protected String getServiceName() {
        return serviceName;
    }

    protected MetricRegistry getMetrics() {
        return metrics;
    }

    public Counter newCounter(Class<?> tClass, String metricUniqMark) {
        String name = metricName(tClass, metricUniqMark);
        return metrics.counter(name);

    }

    public Histogram newHistogram(Class<?> tClass, String metricUniqMark) {
        String name = metricName(tClass, metricUniqMark);
        return metrics.histogram(name);
    }

    public <T> Gauge<T> newGauge(Gauge<T> gauge, Class<?> tClass, String metricUniqMark) {
        String name = metricName(tClass, metricUniqMark);
        return metrics.register(name, gauge);
    }

    public Meter newMeter(Class<?> tClass, String metricUniqMark) {
        String name = metricName(tClass, metricUniqMark);
        return metrics.meter(name);
    }

    public Timer newTimer(Class<?> tClass, String metricUniqMark) {
        String name = metricName(tClass, metricUniqMark);
        return metrics.timer(name);
    }

    protected String metricName(Class<?> tClass, String metricUniqMark) {
        String name = MetricRegistry.name(IpAddress,
                serviceName,
                String.valueOf(factoryId),
                tClass.getName(),
                metricUniqMark);
        return name;
    }

    public void destroyAllMetrics() {
        String rmNameTags = MetricRegistry.name(IpAddress,
                serviceName,
                String.valueOf(factoryId));
        removeMetrics(rmNameTags);
    }

    public void destroyMetricByMark(String metricUniqMark) {
        String rmNameTags = MetricRegistry.name(IpAddress,
                serviceName,
                String.valueOf(factoryId),
                ".*",
                metricUniqMark);
        removeMetrics(rmNameTags);
    }

    public void destroyMetric(final Metric pMetric) {
        metrics.removeMatching(new MetricFilter() {
            public boolean matches(String name, Metric metric) {
                return pMetric == metric;
            }
        });
    }

    private final void removeMetrics(String rmNameTags) {
        final Pattern rmPat = Pattern.compile(".*" + rmNameTags + ".*");
        metrics.removeMatching(new MetricFilter() {
            public boolean matches(String name, Metric metric) {
                return rmPat.matcher(name).matches();
            }
        });
    }

}
